/*
 *所有关于Mds_LogisticTask类的业务代码应在此处编写
 *可使用repository.调用常用方法，获取EF/Dapper等信息
 *如果需要事务请使用repository.DbContextBeginTransaction
 *也可使用DBServerProvider.手动获取数据库相关信息
 *用户信息、权限、角色等使用UserContext.Current操作
 *Mds_LogisticTaskService对增、删、改查、导入、导出、审核业务代码扩展参照ServiceFunFilter
 */

using DGZImp.BasProject.DomainModels;
using DGZImp.Core.DbSqlSugar;
using DGZImp.Core.Exceptions;
using DGZImp.Core.Extensions;
using DGZImp.Core.Services;
using DGZImp.Core.Utilities;
using DGZImp.MdsProject.Devices;
using DGZImp.MdsProject.Devices.Entities;
using DGZImp.MdsProject.Devices.Models;
using DGZImp.MdsProject.DomainModels;
using DGZImp.MdsProject.Helper;
using DGZImp.MdsProject.IRepositories;
using DGZImp.MdsProject.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using SqlSugar;

namespace DGZImp.MdsProject.Services
{
    public partial class Mds_LogisticTaskService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IMds_LogisticTaskRepository _repository;//访问数据库

        public MdsInit mdsInit = AutofacContainerModule.GetService<MdsInit>();

        [ActivatorUtilitiesConstructor]
        public Mds_LogisticTaskService(
            IMds_LogisticTaskRepository dbRepository,
            IHttpContextAccessor httpContextAccessor
            )
        : base(dbRepository)
        {
            _httpContextAccessor = httpContextAccessor;
            _repository = dbRepository;
            //多租户会用到这init代码，其他情况可以不用
            //base.Init(dbRepository);
        }

        private static List<Mds_LogisticTaskLog> MsgCacheList = new List<Mds_LogisticTaskLog>();

        public override WebResponseContent Add(SaveModel saveDataModel)
        {
            AddOnExecuting = (Mds_LogisticTask task, object list) =>
            {
                var webResponse = new WebResponseContent();
                try
                {
                    AddLogisticTask(task).Wait();
                }
                catch (Exception e)
                {
                    return webResponse.Error(e.Message);
                }
                webResponse.Code = "-1";
                return webResponse.OK();
            };
            return base.Add(saveDataModel);
        }

        /// <summary>
        /// 创建物流任务，必填：起点与终点；选填：物流任务类型
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task AddLogisticTask(Mds_LogisticTask req)
        {
            if (!(req.BeginSiteId > 0) || !(req.EndSiteId > 0))
            {
                throw new AppException("请选择起点与终点");
            }

            var db = _repository.DbContext;
            Mds_LogisticType typeData = null;
            var typeList = await db.Set<Mds_LogisticType>()
                .WhereIF(req.LogisticTypeId > 0, x => x.LogisticTypeId == req.LogisticTypeId)
                .ToListAsync();
            var detailList = await db.Set<Mds_LogisticTypeDetail>()
                .LeftJoin<Mds_LogisticLine>((a, b) => a.LogisticLineId == b.LogisticLineId)
                .Where((a, b) => typeList.Select(x => x.LogisticTypeId).ToArray().Contains(a.LogisticTypeId))
                .OrderBy((a, b) => a.Seq)
                .Select((a, b) => new
                {
                    a.LogisticTypeId,
                    a.Seq,
                    b.LogisticLineId,
                    b.FromSites,
                    b.ToSites,
                    b.MachineIds,
                })
                .ToListAsync();
            foreach (var item in typeList)
            {
                //判断item对应的detail列表数据中，是否有符合要求的数据
                var detail = detailList.Where(x => x.LogisticTypeId == item.LogisticTypeId).ToList();
                if (detail.Count > 0)
                {
                    var fromSites = detail.Select(x => x.FromSites).First()?.Split(',');
                    var toSites = detail.Select(x => x.ToSites).Last()?.Split(',');
                    if (fromSites.Contains(req.BeginSiteId.ToString()) && toSites.Contains(req.EndSiteId.ToString()))
                    {
                        typeData = item;
                        break;
                    }
                }
            }
            if (typeData == null)
            {
                if (req.LogisticTypeId > 0)
                    throw new AppException($"起点与终点与物流任务类型不匹配，请检查");
                else
                    throw new AppException($"起点与终点未能匹配到合适的物流任务类型，请检查");
            }
            var logisticSiteAlais = await db.Set<Mds_LogisticSiteAlias>().ToListAsync();
            var logisticSites = await db.Set<Mds_LogisticSite>().ToListAsync();

            detailList = detailList.Where(x => x.LogisticTypeId == typeData.LogisticTypeId).ToList();
            req.LogisticTaskId = new IdWorker().NextId();
            req.LogisticTypeId = typeData.LogisticTypeId;
            req.TaskStatus = (int)LogisticTaskStatus.新创建;
            var details = new List<Mds_LogisticTaskDetail>();
            for (int i = 0; i < detailList.Count; i++)
            {
                var item = detailList[i];
                var detailItem = new Mds_LogisticTaskDetail()
                {
                    LogisticTaskId = req.LogisticTaskId,
                };
                var beginSite = item.FromSites.Split(',');
                var endSite = item.ToSites.Split(',');
                var machines = item.MachineIds.Split(',');
                if (i == 0)
                {
                    detailItem.BeginSiteId = req.BeginSiteId;
                }
                else if (beginSite.Length == 1)
                {
                    detailItem.BeginSiteId = Convert.ToInt64(beginSite[0]);
                }
                else
                {
                    detailItem.BeginSiteId = Convert.ToInt64(beginSite[new Random().Next(0, beginSite.Length)]);
                }
                if (i == detailList.Count - 1)
                {
                    detailItem.EndSiteId = req.EndSiteId;
                }
                else if (endSite.Length == 1)
                {
                    detailItem.EndSiteId = Convert.ToInt64(endSite[0]);
                }
                else
                {
                    detailItem.EndSiteId = Convert.ToInt64(endSite[new Random().Next(0, endSite.Length)]);
                }
                //TODO 设备分配 理论上由 AGV调度分配后再回写，不可采用随机方式指定小车
                detailItem.MachineId = Convert.ToInt64(machines[new Random().Next(0, machines.Length)]);
                detailItem.LogisticLineId = item.LogisticLineId;
                detailItem.TaskStatus = (int)LogisticTaskStatus.新创建;
                detailItem.BeginSiteAlias = logisticSiteAlais.Where(x => x.LogisticSiteId == detailItem.BeginSiteId
                    && x.MachineId == detailItem.MachineId)
                    .Select(x => x.SiteCodeAlias).FirstOrDefault();
                if (detailItem.BeginSiteAlias.IsNullOrEmpty())
                {
                    detailItem.BeginSiteAlias = logisticSites.Where(x => x.LogisticSiteId == detailItem.BeginSiteId)
                        .Select(x => x.SiteCode).FirstOrDefault();
                }
                detailItem.EndSiteAlias = logisticSiteAlais
                    .Where(x => x.LogisticSiteId == detailItem.EndSiteId && x.MachineId == detailItem.MachineId)
                    .Select(x => x.SiteCodeAlias)
                    .FirstOrDefault();
                if (detailItem.EndSiteAlias.IsNullOrEmpty())
                {
                    detailItem.EndSiteAlias = logisticSites.Where(x => x.LogisticSiteId == detailItem.EndSiteId)
                        .Select(x => x.SiteCode).FirstOrDefault();
                }
                detailItem.Seq = i + 1;
                detailItem.TaskNo = SimpleSnowId.GenerateId();
                details.Add(detailItem);
            }
            db.Ado.BeginTran();
            try
            {
                await db.DoInsertAsync(req);
                await db.DoInsertAsync(details);
                db.Ado.CommitTran();
            }
            catch (Exception e)
            {
                db.Ado.RollbackTran();
                SysLogger.LogError(e, e.Message);
            }
        }

        /// <summary>
        /// 接收到任务明细的执行反馈后获取任务明细信息
        /// </summary>
        /// <param name="taskNo"></param>
        /// <returns></returns>
        public async Task<Mds_LogisticTaskDetail> GetTaskDetailByNo(int taskNo)
        {
            var db = _repository.DbContext;
            var taskDetail = await db.Set<Mds_LogisticTaskDetail>()
                    .Where(t => t.TaskNo == taskNo)
                    .OrderBy(t => t.LogisticTaskDetailId, OrderByType.Desc)
                    .FirstAsync();
            return taskDetail;
        }

        /// <summary>
        /// 接收到任务明细的执行反馈后更新物流任务
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task UpdateLogisticTask(Mds_LogisticTaskDetail req)
        {
            var db = _repository.DbContext;
            db.Ado.BeginTran();
            try
            {
                await db.DoUpdateAsync(req);

                // 更新起始点与目标点占用状态
                await db.DoUpdateAsync<Mds_LogisticSite>(new
                {
                    Occupied = false
                }, x => x.LogisticSiteId == req.BeginSiteId && x.IsValid == 1 && x.Enabled == 1);
                await db.DoUpdateAsync<Mds_LogisticSite>(new
                {
                    Occupied = true
                }, x => x.LogisticSiteId == req.EndSiteId && x.IsValid == 1 && x.Enabled == 1);

                var details = await db.Set<Mds_LogisticTaskDetail>()
                    .Where(x => x.LogisticTaskId == req.LogisticTaskId)
                    .ToListAsync();
                if (details.All(x => x.TaskStatus == (int)LogisticTaskStatus.已完成))
                {
                    await db.DoUpdateAsync<Mds_LogisticTask>(new
                    {
                        TaskStatus = (int)LogisticTaskStatus.完成中,
                        EndTime = DateTime.Now,
                    }, x => x.LogisticTaskId == req.LogisticTaskId && x.TaskStatus != (int)LogisticTaskStatus.已完成 && x.TaskStatus != (int)LogisticTaskStatus.完成中);
                }
                else if (details.All(x => x.TaskStatus == (int)LogisticTaskStatus.已完成 || x.TaskStatus == (int)LogisticTaskStatus.已取消))
                {
                    await db.DoUpdateAsync<Mds_LogisticTask>(new
                    {
                        TaskStatus = (int)LogisticTaskStatus.已取消,
                    }, x => x.LogisticTaskId == req.LogisticTaskId && x.TaskStatus != (int)LogisticTaskStatus.已完成 && x.TaskStatus != (int)LogisticTaskStatus.已取消);
                }
                db.Ado.CommitTran();
            }
            catch (Exception e)
            {
                db.Ado.RollbackTran();
                SysLogger.LogError(e, e.Message);
            }
        }


        /// <summary>
        /// 启动物流任务
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task StartLogisticTask(long? taskId)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_LogisticTask>()
                .Where(x => x.LogisticTaskId == taskId)
                .FirstAsync();
            if (task == null)
            {
                throw new AppException("未找到对应的物流任务");
            }
            if (task.TaskStatus != (int)LogisticTaskStatus.新创建)
            {
                throw new AppException("当前物流任务状态不允许启动");
            }
            await db.DoUpdateAsync<Mds_LogisticTask>(new
            {
                TaskStatus = (int)LogisticTaskStatus.准备中,
            }, x => x.LogisticTaskId == task.LogisticTaskId);
        }

        /// <summary>
        /// 取消物流任务
        /// </summary>
        public async Task CancleLogisticTask(long? taskId)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_LogisticTask>()
                .Where(x => x.LogisticTaskId == taskId)
                .FirstAsync();
            if (task == null)
            {
                throw new AppException("未找到对应的物流任务");
            }
            if (task.TaskStatus == (int)LogisticTaskStatus.已完成 ||
                task.TaskStatus == (int)LogisticTaskStatus.完成中 ||
                task.TaskStatus == (int)LogisticTaskStatus.已取消)
            {
                throw new AppException("当前物流任务状态不允许取消");
            }
            await db.DoUpdateAsync<Mds_LogisticTask>(new
            {
                TaskStatus = (int)LogisticTaskStatus.已取消,
            }, x => x.LogisticTaskId == task.LogisticTaskId);
        }

        /// <summary>
        /// 强制完成物流任务
        /// </summary>
        public async Task ForceCompletLogisticTask(long? taskId)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_LogisticTask>()
                .Where(x => x.LogisticTaskId == taskId)
                .FirstAsync();
            if (task == null)
            {
                throw new AppException("未找到对应的物流任务");
            }
            if (task.TaskStatus == (int)LogisticTaskStatus.已完成 ||
                task.TaskStatus == (int)LogisticTaskStatus.完成中 ||
                task.TaskStatus == (int)LogisticTaskStatus.已取消)
            {
                throw new AppException("当前物流任务状态不允许强制完成");
            }

            await db.DoUpdateAsync<Mds_LogisticTask>(new
            {
                TaskStatus = (int)LogisticTaskStatus.完成中,
            }, x => x.LogisticTaskId == task.LogisticTaskId);

            await AddTaskLog(task.LogisticTaskId, LogMessageType.提示, "手动强制完成当前任务");
        }

        /// <summary>
        /// 手动完成单笔物流任务明细
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="taskNo"></param>
        /// <returns></returns>
        public async Task FinishLogisticDetailTask(long? taskId, int? taskNo)
        {
            var db = _repository.DbContext;
            var task = await db.Set<Mds_LogisticTaskDetail>()
                .WhereIF(taskId != null && taskId > 0, x => x.LogisticTaskDetailId == taskId)
                .WhereIF(taskNo != null && taskNo > 0, x => x.TaskNo == taskNo)
                .FirstAsync();
            if (task == null)
            {
                SysLogger.LogWarning($"接收到物流任务[{taskId ?? taskNo}]完成信息，但未找到对应的物流任务明细");
                return;
            }
            if (task.TaskStatus == (int)LogisticTaskStatus.完成中 || task.TaskStatus == (int)LogisticTaskStatus.已完成 ||
                task.TaskStatus == (int)LogisticTaskStatus.已取消)
            {
                SysLogger.LogWarning($"接收到物流任务[{taskId ?? taskNo}]完成信息，但物流任务明细已经完成或取消");
                return;
            }

            task.TaskStatus = (int)LogisticTaskStatus.已完成;
            task.EndTime = DateTime.Now;

            await UpdateLogisticTask(task);
        }

        /// <summary>
        /// 自动派发物流任务
        /// </summary>
        public async Task AutoSendLogisticTask()
        {
            var db = _repository.DbContext;
            // 获取所有准备中或进行中的物流任务
            var taskList = await db.Set<Mds_LogisticTask>()
                .LeftJoin<Mds_LogisticType>((x, y) => x.LogisticTypeId == y.LogisticTypeId && y.IsValid == 1)
                .Where(x => x.TaskStatus == (int)LogisticTaskStatus.准备中 || x.TaskStatus == (int)LogisticTaskStatus.进行中)
                .Select((x, y) => new
                {
                    x.LogisticTaskId,
                    y.LogisticType,
                    x.TaskStatus
                })
                .ToListAsync();
            // 获取所有未完成的物流任务详情
            var detailList = await db.Set<Mds_LogisticTaskDetail>()
                .Where(x => SqlFunc.ContainsArray(taskList.Select(n => n.LogisticTaskId).ToList(), x.LogisticTaskId))
                .OrderBy(x => x.Seq)
                .ToListAsync();
            foreach (var item in taskList)
            {
                try
                {
                    var taskDetail = detailList.Where(x => x.LogisticTaskId == item.LogisticTaskId).ToList();
                    if (!taskDetail.Any(x => x.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                        x.TaskStatus == (int)LogisticTaskStatus.准备中 || x.TaskStatus == (int)LogisticTaskStatus.进行中))
                    {
                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, "无待执行的子任务，主任务即将完成");
                        await db.DoUpdateAsync<Mds_LogisticTask>(new { TaskStatus = (int)LogisticTaskStatus.完成中 },
                                x => x.LogisticTaskId == item.LogisticTaskId);
                        continue;
                    }
                    else
                    {
                        var detail = taskDetail.First(x => x.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                            x.TaskStatus == (int)LogisticTaskStatus.准备中 || x.TaskStatus == (int)LogisticTaskStatus.进行中);
                        if (detail == null) continue;
                        if (detail != null && detail.TaskStatus == (int)LogisticTaskStatus.进行中) continue;

                        #region 任务下发的一些特殊逻辑控制  HADRCODE site [99, 6] for RGV

                        if (item.LogisticType == (int)LogisticTaskTypeEnum.压机_细粉空罐入空罐线)
                        {
                            var realDevice = await mdsInit.GetRealDeviceByMachineId(detail.MachineId);
                            if (realDevice != null && realDevice.Type == RealDeviceTypeEmun.RGV)
                            {
                                // 需要判断当前没有上料任务，有则不下发，优先上料，通过所有人池中的任务判定是否有即将要下发的上料任务
                                var upTask = detailList.FirstOrDefault(x => x.MachineId == detail.MachineId &&
                                    (x.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                                    x.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                                    x.TaskStatus == (int)LogisticTaskStatus.进行中) &&
                                    x.BeginSiteAlias == "99"
                                );
                                if (upTask != null)
                                {
                                    await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, "存在将要执行的上料任务，需等待");
                                    continue;
                                }
                            }
                        }
                        else if (item.LogisticType == (int)LogisticTaskTypeEnum.气流磨_粗粉空罐回缓存位)
                        {
                            var realDevice = await mdsInit.GetRealDeviceByMachineId(detail.MachineId);
                            if (realDevice != null && realDevice.Type == RealDeviceTypeEmun.RGV)
                            {
                                // 需要判断当前没有上料任务，有则不下发，优先上料
                                var upTask = taskDetail.FirstOrDefault(x => x.MachineId == detail.MachineId &&
                                    (x.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                                    x.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                                    x.TaskStatus == (int)LogisticTaskStatus.进行中) &&
                                    x.BeginSiteAlias == "6"
                                );
                                if (upTask != null)
                                {
                                    await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, "存在将要执行的上料任务，需等待");
                                    continue;
                                }
                            }
                        }
                        else if (item.LogisticType == (int)LogisticTaskTypeEnum.配粉_下线至气流磨上料)
                        {
                            var realDevice = await mdsInit.GetRealDeviceByMachineId(detail.MachineId);
                            if (realDevice != null && realDevice.Type == RealDeviceTypeEmun.AGV_ZY)
                            {
                                //需要判断当前没有进行中的下空罐任务，才能下发给AGV执行，否则可能会堵住RGV取放口
                                //判断提升机是否存在待执行任务,待定
                                //找到此任务使用的RGV
                                var rgvId = taskDetail.FirstOrDefault(x => x.BeginSiteAlias == "6")?.MachineId;
                                if (rgvId != null)
                                {
                                    var rgvDevice = await mdsInit.GetRealDeviceByMachineId(rgvId);
                                    var rgv = (Rgv)rgvDevice.Device;
                                    if (rgv.Data.Status == RgvStatusEmun.未知)
                                    {
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前状态 {rgv.Data.Status} 异常 ，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status != RgvStatusEmun.空闲 && rgv.Data.IsFull == GoodsStatusEnum.有货)
                                    {
                                        //有货但空闲说明是在99等待下空罐
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status} 但光电有货，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status == RgvStatusEmun.运行中 && rgv.Data.End == 99 && rgv.Data.IsFull == GoodsStatusEnum.有货)
                                    {
                                        //正在带着罐去99
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status} 且 光电有货，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status == RgvStatusEmun.运行中 && rgv.Data.Start == 99 && rgv.Data.IsFull == GoodsStatusEnum.无货)
                                    {
                                        //正在准备去上对接取罐子
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status}，需等待");
                                        continue;
                                    }
                                }
                            }
                        }
                        else if (item.LogisticType == (int)LogisticTaskTypeEnum.混粉机_下线至压机上料)
                        {
                            var realDevice = await mdsInit.GetRealDeviceByMachineId(detail.MachineId);
                            if (realDevice != null && realDevice.Type == RealDeviceTypeEmun.AGV_DG)
                            {
                                //需要判断当前没有进行中的下空罐任务，才能下发给AGV执行，否则可能会堵住RGV取放口
                                //找到此任务使用的RGV
                                var rgvId = taskDetail.FirstOrDefault(x => x.BeginSiteAlias == "99")?.MachineId;
                                if (rgvId != null)
                                {
                                    var rgvDevice = await mdsInit.GetRealDeviceByMachineId(rgvId);
                                    var rgv = (Rgv)rgvDevice.Device;
                                    if (rgv.Data.Status == RgvStatusEmun.未知)
                                    {
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前状态 {rgv.Data.Status} 异常 ，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status != RgvStatusEmun.空闲 && rgv.Data.IsFull == GoodsStatusEnum.有货)
                                    {
                                        //有货但空闲说明是在99等待下空罐
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status} 但光电有货，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status == RgvStatusEmun.运行中 && rgv.Data.End == 99 && rgv.Data.IsFull == GoodsStatusEnum.有货)
                                    {
                                        //正在带着罐去99
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status} 且 光电有货，需等待");
                                        continue;
                                    }
                                    if (rgv.Data.Status == RgvStatusEmun.运行中 && rgv.Data.Start == 99 && rgv.Data.IsFull == GoodsStatusEnum.无货)
                                    {
                                        //正在准备去上对接取罐子
                                        await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"RGV {rgv.Name} 当前 {rgv.Data.Status}，需等待");
                                        continue;
                                    }
                                }
                            }
                        }
                        #endregion

                        if (detail.TaskStatus == (int)LogisticTaskStatus.新创建 || detail.TaskStatus == (int)LogisticTaskStatus.准备中)
                        {
                            await AddTaskLog(item.LogisticTaskId, LogMessageType.提示, $"尝试下发子任务，序号[{detail.Seq}]");
                            await mdsInit.SendLogisticTaskToDevice(detail);

                            db.Ado.BeginTran();
                            try
                            {
                                await db.DoUpdateAsync<Mds_LogisticTaskDetail>(new
                                {
                                    TaskStatus = (int)LogisticTaskStatus.进行中,
                                    BeginTime = DateTime.Now
                                }, x => x.LogisticTaskDetailId == detail.LogisticTaskDetailId);
                                var mainTaskStatus = taskList.Where(x => x.LogisticTaskId == item.LogisticTaskId)
                                        .Select(x => x.TaskStatus).FirstOrDefault();
                                if (mainTaskStatus != (int)LogisticTaskStatus.进行中)
                                {
                                    await db.DoUpdateAsync<Mds_LogisticTask>(new
                                    {
                                        TaskStatus = (int)LogisticTaskStatus.进行中,
                                        BeginTime = DateTime.Now
                                    }, x => x.LogisticTaskId == item.LogisticTaskId);
                                }

                                await AddTaskLog(item.LogisticTaskId, LogMessageType.成功, $"子任务[{detail.Seq}]已下发");
                                db.Ado.CommitTran();
                            }
                            catch (Exception)
                            {
                                db.Ado.RollbackTran();
                                throw;
                            }
                        }
                        //处理下一任务,确认是否可以并行，若有则同步下发
                        var nextTask = taskDetail.Where(it => it.Seq == detail.Seq + 1).FirstOrDefault();
                        await ProcessNextTaskToDevice(detail, nextTask);
                    }
                }
                catch (Exception e)
                {
                    SysLogger.LogError(e, "自动派发物流任务异常");
                    await AddTaskLog(item.LogisticTaskId, LogMessageType.错误, $"子任务下发失败：{e.Message}");
                    continue;
                }
            }
        }

        /// <summary>
        /// 处理下发并行任务
        /// </summary>
        /// <param name="currentTask"></param>
        /// <param name="nextTask"></param>
        /// <returns></returns>
        private async Task ProcessNextTaskToDevice(Mds_LogisticTaskDetail currentTask, Mds_LogisticTaskDetail nextTask)
        {
            var db = _repository.DbContext;
            if (nextTask == null || currentTask == null) return;
            var realDevice = await mdsInit.GetRealDeviceByMachineId(currentTask.MachineId);
            var nextDevice = await mdsInit.GetRealDeviceByMachineId(nextTask.MachineId);
            if (nextDevice == null) return;
            if (nextDevice.Type == RealDeviceTypeEmun.RGV)
            {
                var rgv = (Rgv)nextDevice.Device;
                if (rgv.Data.Status != RgvStatusEmun.空闲)
                {
                    await AddTaskLog(currentTask.LogisticTaskId, LogMessageType.提示, $"下发同步子任务，设备 {rgv.Name} 状态 {rgv.Data.Status}，非空闲");
                    return;
                };
                if (rgv.Data.CurPos == Convert.ToInt32(nextTask.BeginSiteAlias)) return;
            }
            else if (nextDevice.Type == RealDeviceTypeEmun.Hoister)
            {
                var hoister = (Hoister)nextDevice.Device;
                if (hoister.Data.Status != HoistStatusEmun.空闲)
                {
                    await AddTaskLog(currentTask.LogisticTaskId, LogMessageType.提示, $"下发同步子任务，设备 {hoister.Name} 状态 {hoister.Data.Status}，非空闲");
                    return;
                };
                if (hoister.Data.CurPos == Convert.ToInt32(nextTask.BeginSiteAlias)) return;
            }
            await AddTaskLog(currentTask.LogisticTaskId, LogMessageType.提示, $"尝试同步下发并行子任务，序号[{nextTask.Seq}]");
            //TODO:下发任务时，需检查RGV、提升机等设备是否运行中，以及有其他任务在执行
            var taskFlag = await mdsInit.SendLogisticTaskToDevice(realDevice, (int)nextTask.TaskNo, nextTask);
            if (!taskFlag)
            {
                await AddTaskLog(nextTask.LogisticTaskId, LogMessageType.成功, $"同步下发并行 移动任务，序号[{nextTask.Seq}] 已下发");
                return;
            }

            db.Ado.BeginTran();
            try
            {
                await db.DoUpdateAsync<Mds_LogisticTaskDetail>(new
                {
                    TaskStatus = (int)LogisticTaskStatus.进行中,
                    BeginTime = DateTime.Now
                }, x => x.LogisticTaskDetailId == nextTask.LogisticTaskDetailId);
                await AddTaskLog(nextTask.LogisticTaskId, LogMessageType.成功, $"并行子任务[{nextTask.Seq}]已下发");
                db.Ado.CommitTran();
            }
            catch (Exception)
            {
                db.Ado.RollbackTran();
                throw;
            }
        }

        /// <summary>
        /// 手动下发一个物流任务的子任务，特殊情况使用
        /// </summary>
        public async Task<bool> ManualSendLogisticTask(long? taskId)
        {
            var db = _repository.DbContext;
            var taskDetail = await db.Set<Mds_LogisticTaskDetail>()
                .Where(x => x.LogisticTaskId == taskId)
                .OrderBy(x => x.Seq)
                .ToListAsync();
            try
            {
                await AddTaskLog(taskId, LogMessageType.提示, $"手动或事件触发任务下发");
                var detail = taskDetail.First(x => x.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                    x.TaskStatus == (int)LogisticTaskStatus.准备中 || x.TaskStatus == (int)LogisticTaskStatus.进行中);
                if (detail == null) throw new Exception("无待执行的子任务");
                if (detail != null && detail.TaskStatus == (int)LogisticTaskStatus.进行中)
                    throw new Exception("当前子任务已执行中");

                if (detail.TaskStatus == (int)LogisticTaskStatus.新创建 || detail.TaskStatus == (int)LogisticTaskStatus.准备中)
                {
                    await AddTaskLog(taskId, LogMessageType.提示, $"尝试下发子任务，序号[{detail.Seq}]");
                    await mdsInit.SendLogisticTaskToDevice(detail);
                    db.Ado.BeginTran();
                    try
                    {
                        await db.DoUpdateAsync<Mds_LogisticTaskDetail>(new
                        {
                            TaskStatus = (int)LogisticTaskStatus.进行中,
                            BeginTime = DateTime.Now
                        }, x => x.LogisticTaskDetailId == detail.LogisticTaskDetailId);
                        await db.DoUpdateAsync<Mds_LogisticTask>(new
                        {
                            TaskStatus = (int)LogisticTaskStatus.进行中,
                            BeginTime = DateTime.Now
                        }, x => x.LogisticTaskId == taskId);
                        await AddTaskLog(taskId, LogMessageType.成功, $"子任务[{detail.Seq}]已下发");
                        db.Ado.CommitTran();
                        return true;
                    }
                    catch (Exception)
                    {
                        db.Ado.RollbackTran();
                        throw;
                    }
                }
            }
            catch (Exception e)
            {
                SysLogger.LogError(e, "手动下发物流任务异常");
                await AddTaskLog(taskId, LogMessageType.错误, $"子任务下发失败：{e.Message}");
            }
            return false;
        }


        /// <summary>
        /// 自动处理主任务完成
        /// </summary>
        /// <returns></returns>
        public async Task AutoCompleteLogisticTask()
        {
            var db = _repository.DbContext;
            var taskList = await db.Set<Mds_LogisticTask>()
                .LeftJoin<Mds_LogisticType>((x, b) => x.LogisticTypeId == b.LogisticTypeId)
                .Where(x => x.TaskStatus == (int)LogisticTaskStatus.完成中)
                .Select((x, b) => new
                {
                    x.LogisticTaskId,
                    x.LogisticTypeId,
                    x.BeginSiteId,
                    x.EndSiteId,
                    b.LogisticType
                })
                .ToListAsync();
            foreach (var item in taskList)
            {
                db.Ado.BeginTran();
                try
                {
                    // 整个物流任务完成时 根据不同的任务类型做特殊处理
                    switch ((LogisticTaskTypeEnum)item.LogisticType)
                    {
                        case LogisticTaskTypeEnum.压机_细粉空罐入空罐线:
                        case LogisticTaskTypeEnum.配粉_氢破空罐入空罐线:
                            var site = await db.Set<Mds_LogisticSiteAlias>()
                                .LeftJoin<Mds_RealDevice>((a, b) => a.RealDeviceId == b.RealDeviceId)
                                .Where((a, b) => a.LogisticSiteId == item.EndSiteId)
                                .Where((a, b) => b.Category == (int)RealDeviceTypeEmun.Conveyor)
                                .FirstAsync();
                            if (site == null)
                                throw new AppException("空罐线放罐任务完成，但未找到对应的输送线设备配置，无法发送放罐完成信号");
                            var device = mdsInit.devices.Where(x => x.Device is Conveyor && ((Conveyor)x.Device).Id == site.RealDeviceId.ToString())
                                .FirstOrDefault();
                            if (device == null)
                                throw new AppException("空罐线放罐任务完成，但未找到对应的输送线设备实体，无法发送放罐完成信号,realdeviceid:" + site.RealDeviceId.ToString());
                            var res = await ((Conveyor)device.Device).SendCommandAsync(ConveyorCommandEnum.取放罐完成);
                            if (res.IsSuccess)
                                await AddTaskLog(item.LogisticTaskId, LogMessageType.成功, "下发放罐完成信号");
                            else
                                await AddTaskLog(item.LogisticTaskId, LogMessageType.错误, "下发放罐完成信号失败，" + res.Message);
                            break;
                        default:
                            break;
                    }
                    await db.DoUpdateAsync<Mds_LogisticTask>(new
                    {
                        TaskStatus = (int)LogisticTaskStatus.已完成,
                        EndTime = DateTime.Now
                    }, x => x.LogisticTaskId == item.LogisticTaskId);
                    await AddTaskLog(item.LogisticTaskId, LogMessageType.成功, "任务已完成");
                    db.Ado.CommitTran();
                }
                catch (Exception e)
                {
                    db.Ado.RollbackTran();
                    SysLogger.LogError(e, "自动完成物流任务异常");
                }
            }
        }


        /// <summary>
        /// 添加任务执行日志
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="type"></param>
        /// <param name="message"></param>
        /// <param name="msg1"></param>
        /// <param name="msg2"></param>
        /// <returns></returns>
        public async Task AddTaskLog(long? taskId, LogMessageType type, string message, string msg1 = null, string msg2 = null)
        {
            var lastMsg = MsgCacheList.Where(x => x.LogisticTaskId == taskId && x.LogType == (int)type)
                .FirstOrDefault();
            if (lastMsg != null && lastMsg.LogContent == message &&
                    lastMsg.Msg1 == msg1 &&
                    lastMsg.Msg2 == msg2 &&
                    lastMsg.CreateTime > DateTime.Now.AddMinutes(-5))
            {
                return;
            }
            if (taskId == null || taskId < 1)
            {
                switch (type)
                {
                    case LogMessageType.错误:
                        SysLogger.LogError(message + " " + msg1 + " " + msg2);
                        break;
                    case LogMessageType.警告:
                        SysLogger.LogWarning(message + " " + msg1 + " " + msg2);
                        break;
                    default:
                        SysLogger.LogInformation(message + " " + msg1 + " " + msg2);
                        break;
                };
                return;
            }
            var db = _repository.DbContext;
            var log = new Mds_LogisticTaskLog
            {
                LogisticTaskId = taskId,
                LogType = (int)type,
                LogContent = message,
                Msg1 = msg1,
                Msg2 = msg2,
                CreateTime = DateTime.Now,
            };
            if (lastMsg != null) MsgCacheList.Remove(lastMsg);
            MsgCacheList.Add(log);
            await db.DoInsertAsync(log);
            MsgCacheList.RemoveAll(x => x.CreateTime < DateTime.Now.AddHours(-12));
        }

        /// <summary>
        /// 生成上下对接机构出罐任务
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <param name="taskNo">任务号</param>
        public async Task ProcessConnectorTankTask(string deviceId)
        {
            if (string.IsNullOrEmpty(deviceId)) return;
            var device = mdsInit.devices.Where(x => x.Id == deviceId).FirstOrDefault();
            if (device == null)
            {
                SysLogger.LogError($"监听到上对接机构传入的出罐信号，但是未找到对应设备信息，设备Id: {deviceId}");
                return;
            }

            var db = _repository.DbContext;
            //获取当前设备的主设备
            var masterDeviceCategory = await db.Set<Mds_RealDevice>()
                .Where(a => a.MachineId == device.MachineId && a.IsMasterDevice == 1)
                .FirstOrDefaultAsync();
            if (masterDeviceCategory == null)
            {
                SysLogger.LogError($"当前对接设备 {device.Name}/{device.MachineCode} 未关联生产设备");
                return;
            }
            //通过主设备取设备生产的任务号
            var masterDevice = mdsInit.devices.Where(x => x.Id == masterDeviceCategory.RealDeviceId.ToString()).FirstOrDefault();
            if (masterDevice == null)
            {
                SysLogger.LogError($"当前设备{masterDeviceCategory.DeviceName} 未启动数据采集实例");
                return;
            }

            Int64 taskNo = 0;
            if ((!Int64.TryParse(((Productor)masterDevice.Device).Data.TaskId, out taskNo) || taskNo < 1) &&
                    device.Type != RealDeviceTypeEmun.Connector_TOP)
            {
                SysLogger.LogError($"当前设备 {masterDevice.Name}/{masterDevice.MachineCode} 无生产任务ID信息");
                return;
            }
            //判断是否为 下对接，下对接出罐时，依据下对接关联的 气流磨 生产任务号信息，判定下一序
            if (device.Type == RealDeviceTypeEmun.Connector_BOT)
            {
                var prdTaskService = ServiceProviderAccessor.ServiceProvider.GetService<Mds_ProductionTaskService>();
                await prdTaskService.FinishProductionTask(taskNo);
                await AddTaskLog(taskNo, LogMessageType.成功, $"收到下对接出罐任务信号，并准备下发后续任务");
                return;
            }
            var productionOrder = "";
            if (taskNo > 0)
            {
                productionOrder = await db.Set<Mds_ProductionTask>()
                    .Where(x => x.ProductionTaskId == taskNo)
                    .Select(x => x.WorkOrder).FirstOrDefaultAsync();
            }
            //上对接出空罐
            //获取出罐或出料位置
            var logisticSite = await db.Set<Mds_LogisticSiteInout>()
                .Where(x => x.MachineId == masterDevice.MachineId && x.InFlag == 1)
                .FirstOrDefaultAsync();
            if (logisticSite == null)
            {
                await AddTaskLog(taskNo, LogMessageType.警告, $"当前对接设备 {device.Name}/{device.MachineCode} 未配置空罐出罐位置");
                return;
            }

            int logisticType = (RealDeviceTypeEmun)masterDeviceCategory.Category switch
            {
                RealDeviceTypeEmun.PRD_ZF => (int)LogisticTaskTypeEnum.气流磨_粗粉空罐回缓存位,
                RealDeviceTypeEmun.PRD_YX => (int)LogisticTaskTypeEnum.压机_细粉空罐入空罐线,
                _ => -1
            };
            if (logisticType == -1)
            {
                await AddTaskLog(taskNo, LogMessageType.错误, $"当前对接设备的 主设备类型 无法适用空罐返回业务流程，请确认");
                return;
            }
            var logTypeInfo = await db.Set<Mds_LogisticType>()
                .Where(a => a.LogisticType == logisticType && a.Enabled == 1)
                .FirstOrDefaultAsync();
            // - 是否有起始点位是当前设备的任务
            var hasTask = await db.Set<Mds_LogisticTask>()
                .Where(a => a.TaskStatus == (int)LogisticTaskStatus.新创建 || a.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                            a.TaskStatus == (int)LogisticTaskStatus.进行中)
                .Where(a => a.LogisticTypeId == logTypeInfo.LogisticTypeId && a.BeginSiteId == logisticSite.LogisticSiteId)
                .AnyAsync();

            if (hasTask)
            {
                SysLogger.LogInformation("当前点位已经下发 同类型的 物流任务");
                return;
            }
            // - 获取目的点位
            var targetLogistic = await db.Set<Mds_LogisticSite>()
                .LeftJoin<Mds_LogisticSiteInout>((a, b) => a.LogisticSiteId == b.LogisticSiteId && b.IsValid == 1)
                .Where((a, b) => a.Enabled == 1 && (a.Occupied == null || a.Occupied == 0))
                .Where((a, b) => b.MachineId == masterDevice.MachineId && b.TankOutFlag == 1)
                .Where((a, b) => !SqlFunc.Subqueryable<Mds_LogisticTask>()
                                    .Where(c => c.EndSiteId == a.LogisticSiteId &&
                                                c.IsValid == 1 &&
                                                (c.TaskStatus == (int)LogisticTaskStatus.新创建 ||
                                                 c.TaskStatus == (int)LogisticTaskStatus.准备中 ||
                                                 c.TaskStatus == (int)LogisticTaskStatus.进行中)
                                                ).Any())
                .FirstOrDefaultAsync();

            if (targetLogistic == null)
            {
                await AddTaskLog(null, LogMessageType.错误, $"获取空罐下线目标点位失败，设备Id{deviceId}");
                return;
            }
            // 创建并下发空罐任务
            try
            {
                await AddLogisticTask(new Mds_LogisticTask
                {
                    TaskStatus = (int)LogisticTaskStatus.新创建,
                    LogisticTypeId = logTypeInfo.LogisticTypeId,
                    BeginSiteId = logisticSite.LogisticSiteId,
                    EndSiteId = targetLogistic.LogisticSiteId,
                    WorkOrder = productionOrder
                });
            }
            catch (Exception e)
            {
                await AddTaskLog(null, LogMessageType.警告, $"上料物流任务生成失败，{e.Message}");
            }
        }
    }
}
